﻿using LinqToTwitter;
using soma.Models;
using soma.Models.Resources;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Web.Script.Serialization;

namespace soma.Services
{
    public class TwitterSearch
    {
        private const int MaximumNumberOfEntries = 50;
        private const int DefaultNumberOfEntries = 15;
        private const string TwitterWebsite = "Twitter.com";
        private const string messageUrlFormat = "https://twitter.com/twitter/status/{0}";
        private const string twitterDateFormat = "ddd MMM dd HH:mm:ss zzzz yyyy";
        private readonly AutoResetEvent _signal = new AutoResetEvent(false);

        private TwitterContext twitterCtx;
        private object lockTwitterSearch = new object();

        public TwitterSearch()
        {
            var auth = new SingleUserAuthorizer
            {
                Credentials = new SingleUserInMemoryCredentials
                {
                    ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
                    ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"],
                    TwitterAccessToken = ConfigurationManager.AppSettings["twitterAccessToken"],
                    TwitterAccessTokenSecret = ConfigurationManager.AppSettings["twitterAccessTokenSecret"]
                }
            };

            auth.Authorize();
            twitterCtx = new TwitterContext(auth);
        }

        public void SearchMessagesByTag(List<Tag> tagsToSearch)
        {
            try
            {
                string tags = string.Empty;
                int totatNoTags = 0;
                foreach (Tag t in tagsToSearch)
                {
                    tags += t.TagName + ",";
                    totatNoTags += t.NumberResults;
                }

                if (tags.Count() > 0)
                {
                    tags.Remove(tags.Length - 1);
                }
                int count = 0;

                var messages =
                    (from search in twitterCtx.Streaming
                     where search.Type == StreamingType.Filter && search.Track == tags//&& search.Locations == "-180.0,-90.0,180.0,90.0"
                     // orderby tweet. descending
                     select search).StreamingCallback(strm =>
                    {
                        List<MessageResource> messageResourceList = new List<MessageResource>();

                        if (strm.Status != TwitterErrorStatus.Success)
                        {
                            Console.WriteLine(strm.Error.ToString());
                            return;
                        }

                        Console.WriteLine(strm.Content + "\n");
                        JavaScriptSerializer serializer = new JavaScriptSerializer();
                        Dictionary<string, object> user = (Dictionary<string, object>)serializer.DeserializeObject(strm.Content);

                        if (user != null && user.ContainsKey("lang") && user["lang"].Equals("en") &&
                            !user.ContainsKey("disconnect") && (Dictionary<string, object>)user["coordinates"] != null)
                        {
                            try
                            {
                                object text;
                                object date;
                                object id;

                                user.TryGetValue("text", out text);
                                user.TryGetValue("created_at", out date);
                                user.TryGetValue("id_str", out id);

                                object userName = ((Dictionary<string, object>)(Dictionary<string, object>)user["user"])["name"];
                                object userPhoto = ((Dictionary<string, object>)(Dictionary<string, object>)user["user"])["profile_image_url"];
                                object longi = ((object[])(((Dictionary<string, object>)user["coordinates"])["coordinates"]))[0];
                                object lati = ((object[])(((Dictionary<string, object>)user["coordinates"])["coordinates"]))[1];

                                string keyword = text as string;


                                string tag = string.Empty;
                                bool isSynonym = false;

                                foreach (Tag t in tagsToSearch)
                                {
                                    if (keyword.ToLower().Contains(t.TagName.ToLower()))
                                    {
                                        tag = t.TagName;
                                        isSynonym = (t.Synonyms.Count() == 0);
                                        break;
                                    }
                                }

                                MessageResource messageResource = new MessageResource(string.Format(HashGenerator.GetHashString(messageUrlFormat), id as string), tag);
                                messageResource.Url = string.Format(messageUrlFormat, id as string);
                                messageResource.ThumbnailUrl = userPhoto as string;
                                messageResource.Author = userName as string;

                                if (messageResource.Author == null || messageResource.Author.Equals(string.Empty))
                                {
                                    messageResource.Author = "Check website for more info";
                                }

                                messageResource.IsSynonym = isSynonym;
                                messageResource.Website = TwitterWebsite;
                                messageResource.Message = text as string;
                              

                                if (messageResource.Message != null)
                                {
                                    if (messageResource.Message.Count() > 30)
                                    {
                                        messageResource.Message = messageResource.Message.Substring(0, 30) + "...";
                                    }
                                }

                                messageResource.Date = DateTime.ParseExact(date.ToString(), twitterDateFormat, CultureInfo.InvariantCulture);
                                messageResource.DownloadedDate = DateTime.Now;
                                messageResource.ResourceCoordinates = new Coordinates(Convert.ToDouble(longi), Convert.ToDouble(lati));
                                messageResource.IsSynonym = false;
                                messageResourceList.Add(messageResource);

                                MessagesRepository.Instance.AddResourcesByTag(messageResource.Tag, messageResourceList.Cast<IResource>().ToList());
                                messageResourceList.Clear();
                                count++;
                            }
                            catch (Exception ex)
                            {
                                Console.Error.WriteLine(ex.Message);
                            }
                        }

                        if (count >= totatNoTags)
                        {
                            _signal.Set();
                            strm.CloseStream();
                            count = 0;
                            return;
                        }
                    })
            .SingleOrDefault();
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.Message);
            }

            _signal.WaitOne(30000);
        }
    }
}